from datetime import datetime
from decimal import Decimal
from random import randint

from django.db import transaction
from rest_framework import serializers
from rest_framework.fields import SerializerMethodField
from rest_framework.serializers import ModelSerializer

from shopping.models import Classification, Commodity, CommodityImg, ShoppingCart, Order, OrderGoods, Payment
from users.models import Address


class ClassificationSerializer(ModelSerializer):
    class Meta:
        model = Classification
        fields = '__all__'


class ParentClassificationSerializer(ModelSerializer):
    # 返回该分类下的所有的子级分类
    classification_set = ClassificationSerializer(many=True, read_only=True)

    class Meta:
        model = Classification
        fields = ['id', 'name', 'classification_set']


class CommodityImgSerializer(ModelSerializer):
    class Meta:
        model = CommodityImg
        fields = ['src']


class CommoditySerializer(ModelSerializer):
    # 分类名
    classification1_name = serializers.CharField(source='classification1.name', read_only=True)
    classification2_name = serializers.CharField(source='classification2.name', read_only=True)
    # 图片地址
    commodityimg_set = CommodityImgSerializer(many=True, read_only=True)

    class Meta:
        model = Commodity
        # exclude = ['is_delete']
        fields = '__all__'

        extra_kwargs = {
            'sales': {'read_only': True},
            'comments': {'read_only': True}
        }


class ShoppingCartSerializer(ModelSerializer):
    # 新增数据库不存在的字段 SerializerMethodField类来处理
    # 会自动调用属性名 在属性名之前添加get方法 也就是会调用get_commodityDetail
    # 来获取到对应的商品详情属性
    commodityDetail = SerializerMethodField()

    class Meta:
        model = ShoppingCart
        fields = '__all__'

    def validate(self, attrs):
        user = self.context['request'].user
        # 获取当前登录的用户id 和添加购物车的表单传过来的用户id
        print(user.id, attrs['user'].id)
        # 限制添加购物车商品只能为当前登录的用户
        if user.id != attrs['user'].id:
            raise serializers.ValidationError('非法请求')
        if attrs['number'] <= 0:
            raise serializers.ValidationError("添加购物车的商品数量有误")
        elif attrs['number'] > attrs['commodity'].stock:
            raise serializers.ValidationError("添加购物车的商品数量超出库存值")
        else:
            return attrs

    def get_commodityDetail(self, shoppingcart):
        """
        参数:shoppingcart实例对像
        返回购物车关联的商品信息

        """
        return CommoditySerializer(shoppingcart.commodity).data


class OrderSerializer(ModelSerializer):
    # 购物车传入要结算的商品id列表
    cart = serializers.ListField(write_only=True)

    class Meta:
        model = Order
        fields = "__all__"
        read_only_fields = ['order_id', 'total_count', 'total_amount', 'status', 'users']

    def create(self, validated_data):
        print(123)
        """
        重写创建方法
        已知：客户端会传递要结算的购物车的商品id 支付方式 收货地址id
        validated_data：用户传入的数据
        """
        # 生成订单id 唯一 时间+格式化的6位用户id+两位随机数
        user = self.context['request'].user
        user_id = '%06d' % user.id
        order_id = datetime.now().strftime('%Y%m%d%H%M%S') + user_id[:6] + "%02d" % randint(1, 99)

        # 获取用户选择的支付方式
        pay_method = validated_data.get("pay_method")
        # 获取用户选择的收货地址id
        address = Address.objects.get(id=validated_data.get('address'))

        # 地址拼接成文字字符串
        address_s = f'{address.province.name}{address.city.name}{address.district.name}{address.place}{address.receiver}收'
        with transaction.atomic():
            save_point = transaction.savepoint()
            # 判断sql语句是否会出现问题
            # 如果try里面的sql出现问题的话，则需要回滚到最开始的创建订单
            try:

                # 初始化订单 回到最开始的样式
                order = Order.objects.create(
                    order_id=order_id,
                    total_count=0,
                    total_amount=Decimal('0.00'),
                    pay_method=pay_method,
                    # 如果支付方式选择支付宝，订单状态则为待支付，则为待发货
                    status=1 if pay_method == 1 else 2,
                    address=address_s,
                    users=user,
                )
                print(123)
                # 得到购物车对象
                # 计算商品数量 总额
                carts = validated_data.get('cart')
                # 通过循环依次得到购物车里面的商品做结算
                for cart_id in carts:
                    # 一直尝试对商品进行结算
                    while True:
                        try:
                            cart = ShoppingCart.objects.get(id=cart_id)
                        except ShoppingCart.DoesNotExist:
                            raise serializers.ValidationError("购物信息不存在")
                        community = cart.commodity
                        # 原本商品的库存数量和销量
                        origin_stock = community.stock
                        origin_sales = community.sales
                        # 校验核算后面的商品是否超过库存
                        print(cart.number,origin_stock)
                        if cart.number > origin_stock:
                            raise serializers.ValidationError('库存不足')
                        # 更新库存跟销量
                        new_stock = origin_stock - cart.number
                        new_sales = origin_sales + cart.number

                        # 更新商品表
                        # community.stock = new_stock
                        # community.sales = new_sales
                        # community.save()
                        # 加入乐观锁，更新新 此案查询核对数据有没有发生改变
                        # 条件是旧库存数,如果数量发生改变，则认为其他用户购买成功，库存数发生了改变
                        # 则不能继续做提交订单的操作
                        # 回到最开始的步骤
                        res = Commodity.objects.filter(id=community.id, stock=origin_stock).update(stock=new_stock,
                                                                                                   sales=new_sales)
                        if not res:
                            continue

                        # 如果没有更改执行更新商品的操作

                        # 订单详情数据记录 小票
                        OrderGoods.objects.create(
                            numbers=cart.number,
                            price=community.price,
                            order=order,
                            community=community,
                        )
                        # 更新订单表
                        order.total_count += cart.number
                        # 商品总额等于商品数量*商品单价
                        order.total_amount += (cart.number * community.price)
                        break
                #     创建订单数据
                order.save()

                # 结算完成 删除已结算的购物车中的信息
                ShoppingCart.objects.filter(id__in=carts).delete()
            except Exception as e:
                # 如果try里面的任意一条sql语句出问题都需要回滚到初始化订单的节点
                transaction.savepoint_rollback(save_point)
                raise serializers.ValidationError(e)
            else:
                # 提交到数据库执行以上的mysql语句
                transaction.savepoint_commit(save_point)
        # 最后把订单信息返回给到前端
        return order


class PaymentSerializer(ModelSerializer):
    class Meta:
        model = Payment
        fields = '__all__'
